<?php
/**
 * Project: AIGC
 * Author: moufer <moufer@163.com>
 * Date: 2024/7/7 00:00
 */

namespace module\ai\library\channel\llm;

use module\ai\library\channel\abstract\Llm;
use module\ai\library\channel\completion\AliyunCompletion;
use module\ai\library\channel\interface\CompletionInterface;
use mof\exception\LogicException;
use Psr\Http\Message\ResponseInterface;

class AliyunQwen extends Llm
{
    protected string $baseUrl = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation';

    public static function versions(): array
    {
        return [
            'qwen-turbo'           => 'qwen-turbo',
            'qwen-plus'            => 'qwen-plus',
            'qwen-max'             => 'qwen-max',
            'qwen-max-longcontext' => 'qwen-max-longcontext',
            'qwen-long'            => 'qwen-long',
        ];
    }

    /**
     * @inheritdoc
     */
    public function withMessage(string $message, string $role = 'user', ?array $extra = null,
                                bool   $overload = false): static
    {
        $message = [
            'role'    => $role,
            'content' => $message,
        ];
        if ($extra) {
            $message = array_merge($message, $extra);
        }
        if ($overload) {
            $this->payload['input']['messages'] = [];
        }
        $this->payload['input']['messages'][] = $message;
        return $this;
    }

    /**
     * @inheritdoc
     */
    protected function setPayload(array $config, bool $override = false): void
    {
        parent::setPayload($config, $override);

        $parameters = [
            'seed', 'max_tokens', 'top_p', 'top_k', 'temperature', 'stop',
            'repetition_penalty', 'presence_penalty', 'enable_search',
            'tools', 'tool_choice',
        ];
        foreach ($parameters as $key) {
            if (!empty($config[$key]) || $override) {
                $this->payload['parameters'][$key] = $config[$key];
            }
        }

        //默认值
        $defaultValues = [
            'result_format' => 'message'
        ];
        foreach ($defaultValues as $key => $value) {
            if (empty($this->payload['parameters'][$key])) {
                $this->payload['parameters'][$key] = $value;
            }
        }
    }

    /**
     * @inheritdoc
     */
    protected function getPayload(): array
    {
        $payload = $this->payload;
        $messages = $payload['input']['messages'] ?? null;
        if (empty($messages)) {
            throw new LogicException('未提供消息内容');
        }
        //取最后一条信息
        $message = $messages[count($messages) - 1];
        if ($message['role'] !== 'user') {
            throw new LogicException('未提供用户消息');
        }
        //设置系统信息
        if ($this->system) {
            //添加到头部
            array_unshift($messages, [
                'role'    => 'system',
                'content' => $this->system
            ]);
            $payload['input']['messages'] = $messages;
        }
        if ($this->isStream) {
            $payload['parameters']['incremental_output'] = true;
        }
        return $payload;
    }

    protected function getCompletionStruct(array $data, bool $isStream = false): ?CompletionInterface
    {
        return new AliyunCompletion($data, $isStream);
    }

    protected function getResponse(bool $isStream = false, array $clientOptions = []): ResponseInterface
    {
        return parent::getResponse($isStream, [
            'headers' => [
                'Content-Type'  => 'application/json',
                'Accept'        => $isStream ? 'text/event-stream' : 'application/json',
                'Authorization' => 'Bearer ' . $this->getKeySecret()['key'],
            ]
        ]);
    }

}